<template>
    <div class="flex items-baseline gap-1">
        <!-- 数字滚动容器 -->
        <div class="inline-flex items-end" :style="{
            'font-size': `${fontSize}rem`,
            'font-weight': fontWeight
        }">
            <!-- 每个数字单独处理，实现逐位滚动 -->
            <div v-for="(digit, index) in formattedDigits" :key="index"
                class="relative overflow-hidden inline-block align-top" :style="{
                    width: `${digitWidth}px`,
                    height: `${digitHeight}px`,
                    lineHeight: `${digitHeight}px`
                }">
                <div class="transition-transform duration-500 ease-out" :style="{
                    transform: `translateY(-${currentOffset[index]}%)`,
                    color: textColor
                }">
                    <!-- 滚动数字序列（0-9循环） -->
                    <div class="digit-column">
                        <div>0</div>
                        <div>1</div>
                        <div>2</div>
                        <div>3</div>
                        <div>4</div>
                        <div>5</div>
                        <div>6</div>
                        <div>7</div>
                        <div>8</div>
                        <div>9</div>
                        <div>0</div> <!-- 重复0，使滚动循环更自然 -->
                    </div>
                </div>
            </div>

            <!-- 小数点（如果有） -->
            <div v-if="hasDecimal" class="inline-block align-top text-center" :style="{
                width: '0.5rem',
                color: textColor,
                height: `${digitHeight}px`,
                lineHeight: `${digitHeight + (fontSize * 4)}px`
            }">
                .
            </div>
        </div>

        <!-- 单位（可选） -->
        <span v-if="unit" class="text-gray-600 transition-all align-baseline"
            :style="{ 'font-size': `${fontSize * 0.8}rem` }">
            {{ unit }}
        </span>
    </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch, defineProps, withDefaults } from 'vue';

// 组件属性定义
interface AnimatedNumberProps {
    /** 目标数字 */
    value: number;
    /** 动画时长（毫秒） */
    duration?: number;
    /** 保留小数位数 */
    decimals?: number;
    /** 数字颜色（支持Tailwind类名或颜色值） */
    textColor?: string;
    /** 字体大小（rem） */
    fontSize?: number;
    /** 字体粗细 */
    fontWeight?: string;
    /** 数字单位（如%、$） */
    unit?: string;
    /** 是否添加千分位分隔符 */
    thousandSeparator?: boolean;
}

// 设置默认属性
const props = withDefaults(defineProps<AnimatedNumberProps>(), {
    duration: 1500,
    decimals: 0,
    textColor: 'text-blue-600',
    fontSize: 2,
    fontWeight: 'bold',
    unit: '',
    thousandSeparator: true
});

// 数字滚动核心状态
const currentValue = ref(0);
const currentOffset = ref<number[]>([]);
const previousValue = ref(0);

// 计算数字高度和宽度（基于字体大小动态计算，确保对齐）
const digitHeight = computed(() => Math.floor(props.fontSize * 18)); // 增加高度确保数字完整显示
const digitWidth = computed(() => {
    // 不同字体大小对应不同宽度，确保数字紧凑对齐
    if (props.fontSize < 1.5) return Math.floor(props.fontSize * 10);
    if (props.fontSize < 2.5) return Math.floor(props.fontSize * 11);
    return Math.floor(props.fontSize * 12);
});

// 格式化数字为字符串（处理小数和千分位）
const formattedDigits = computed(() => {
    // 处理小数
    let numStr = currentValue.value.toFixed(props.decimals);

    // 处理千分位
    if (props.thousandSeparator && props.decimals === 0) {
        numStr = numStr.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    }

    // 分割为数字数组（过滤千分位逗号）
    return numStr.split('').filter(c => c !== ',');
});

// 是否包含小数点
const hasDecimal = computed(() => formattedDigits.value.includes('.'));

// 初始化偏移量
const initOffsets = (value: number) => {
    const str = value.toFixed(props.decimals);
    const digits = str.split('').filter(c => c !== ',');
    currentOffset.value = digits.map(d => d === '.' ? 0 : parseInt(d) * 10);
};

// 数字滚动动画
const animateNumber = (start: number, end: number) => {
    const startTime = performance.now();
    const increment = end - start;

    const animate = (timestamp: number) => {
        const elapsed = timestamp - startTime;
        const progress = Math.min(elapsed / props.duration, 1);

        // 使用缓动函数使动画更自然（easeOutCubic）
        const easeProgress = 1 - Math.pow(1 - progress, 3);
        currentValue.value = start + increment * easeProgress;

        // 更新每个数字的偏移量
        const str = currentValue.value.toFixed(props.decimals);
        const digits = str.split('').filter(c => c !== ',');

        // 确保偏移数组长度匹配
        if (digits.length !== currentOffset.value.length) {
            currentOffset.value = new Array(digits.length).fill(0);
        }

        digits.forEach((d, i) => {
            if (d !== '.') {
                currentOffset.value[i] = parseInt(d) * 10;
            }
        });

        if (progress < 1) {
            requestAnimationFrame(animate);
        }
    };

    requestAnimationFrame(animate);
};

// 监听数值变化，触发动画
watch(
    () => props.value,
    (newVal) => {
        animateNumber(previousValue.value, newVal);
        previousValue.value = newVal;
    }
);

// 组件挂载时初始化
onMounted(() => {
    previousValue.value = 0;
    initOffsets(0);
    // 初始动画
    setTimeout(() => {
        animateNumber(0, props.value);
    }, 100);
});
</script>

<style scoped>
/* 数字列样式 - 确保每个数字高度一致 */
.digit-column {
    display: flex;
    flex-direction: column;
    height: 1000%;
    /* 10个数字，每个占10%高度 */
}

.digit-column>div {
    height: 10%;
    /* 每个数字占10%高度 */
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

/* 修复inline-block元素之间的间隙 */
.digit-column>div {
    letter-spacing: 0;
}
</style>
